package structs.term;

import java.sql.Date;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import structs.adoption.Adoption;
import structs.book.Book;
import structs.term.dept.Department;
import structs.term.dept.Department.Code;
import exception.InvalidNameException;

/**
 * Represents a single term of courses. Eg. Fall 2012
 * 
 * @author Tim
 * 
 */
public class Term implements Comparable<Term>{

	public static enum Semester {

		FALL("Fall"), SPRING("Spring"), SUMMER_A("Summer", 'A'), SUMMER_B(
				"Summer", 'B');

		private String id;
		/**
		 * Only used for Summer. 'A' or 'B'
		 */
		private char track;

		/**
		 * Creates a new semester without a track
		 * 
		 * @param id
		 *            Fall/Spring/Summer
		 */
		Semester(String id) {
			this(id, ' ');
		}

		/**
		 * Creates a new semester with the given track
		 * 
		 * @param ID
		 *            Fall/Spring/Summer
		 * @param tr
		 *            A/B
		 */
		Semester(String ID, char tr) {
			id = ID;
			track = tr;
		}

		/**
		 * @return Fall/Spring/Summer
		 */
		public String getID() {
			return id;
		}

		/**
		 * @return 'A' / 'B' / ' '
		 */
		public char getTrack() {
			return track;
		}

		@Override
		public String toString() {
			if (track != ' ')
				return getID() + " " + getTrack();
			else
				return getID();
		}

		public String tableName() {
			if (track != ' ')
				return getID() + getTrack();
			else
				return getID();
		}
	}

	//private static Connection con;
	//private static PreparedStatement pstmt, insertCourse, updateCourse,
	//		insertAdoption, updateAdoption;
	//private static ArrayList<String> dbTerms;

	private static HashMap<Integer, Term> FALLS = new HashMap<Integer,Term>(),
										  SPRINGS = new HashMap<Integer,Term>(),
										  SUMMER_A_S = new HashMap<Integer,Term>(),
										  SUMMER_B_S = new HashMap<Integer,Term>();
	
	private Semester sem;
	private int year;
	private Map<Code, Department> depts;
	private ArrayList<Adoption> adpts;
	private Date startDate, endDate;

	/**
	 * Creates a new term with the given semester and year.
	 * 
	 * @param s
	 *            semester (fall/spring/summerA/summerB)
	 * @param y
	 *            year
	 */
	private Term(Semester s, int y) {
		sem = s;
		year = y;
		initDepartments();
		//dbTerms.add(tableName());
		adpts = new ArrayList<Adoption>();
	}
	
	public void setDates(Date start, Date finish) {
		System.out.println("setting dates start: "+start.toString()+" end: "+finish.toString());
		startDate = start;
		endDate = finish;
	}

	public static Term parse(String termString) {
		
		Term tm = null;

		String[] split = termString.split(" ");
		
		if (split[0].equalsIgnoreCase("fall"))
			tm = getFall(Integer.valueOf(split[1]));
		
		else if (split[0].equalsIgnoreCase("spring"))
			tm = getSpring(Integer.valueOf(split[1]));
		
		else if (split[0].equalsIgnoreCase("summer")) {
			
			if (split[1].equalsIgnoreCase("a"))
				tm = getSummerA(Integer.valueOf(split[2]));
			else if (split[1].equalsIgnoreCase("b"))
				tm = getSummerB(Integer.valueOf(split[2]));
		}
		
		return tm;
	}
	
	public static Term getFall(int year) {
		return getTerm(year,FALLS,Semester.FALL);
	}

	public static Term getSpring(int year) {
		return getTerm(year,SPRINGS,Semester.SPRING);
	}

	public static Term getSummerA(int year) {
		return getTerm(year,SUMMER_A_S,Semester.SUMMER_A);
	}

	public static Term getSummerB(int year) {
		return getTerm(year,SUMMER_B_S,Semester.SUMMER_B);
	}
	
	private static Term getTerm(int year, HashMap<Integer,Term> terms, Semester sem) {
		if (terms.containsKey(year))
			return terms.get(year);
		else {
			terms.put(year, new Term(sem,year));
			return terms.get(year);
		}
	}

	public void initDepartments() {
		depts = Department.initDepts();
	}

	/**
	 * @return the semester
	 */
	public Semester getSemester() {
		return sem;
	}

	/**
	 * @return the year
	 */
	public int getYear() {
		return year;
	}

	/**
	 * @param id
	 *            the dept code (eg MA)
	 * @return the department associated with the given code
	 * @throws InvalidNameException
	 *             if the given id is invalid
	 */
	public Department getDept(Code id) {
		if (depts.containsKey(id))
			return depts.get(id);
		else
			return addDept(new Department(id));
	}

	/**
	 * @param d
	 *            department to add to this term
	 * @return the department added
	 */
	public Department addDept(Department d) {
		depts.put(d.getCode(), d);
		return d;
	}

	/**
	 * @return Semester Year
	 */
	@Override
	public String toString() {
		return sem.toString() + " " + year;
	}

	private String tableName() {
		return sem.tableName() + "_" + year;
	}

	public String courseTableName() {
		return tableName() + "_courses";
	}

	public String adoptionTableName() {
		return tableName() + "_adoptions";
	}

	/**
	 * @param e
	 * @return
	 * @see java.util.ArrayList#add(java.lang.Object)
	 */
	public boolean addAdoption(Adoption e) {
		return adpts.add(e);
	}

	/**
	 * @return
	 * @see java.util.ArrayList#toArray()
	 */
	public Object[] getAdoptionArray() {
		return adpts.toArray();
	}

	/**
	 * @param a
	 * @return
	 * @see java.util.ArrayList#toArray(T[])
	 */
	public <T> T[] toArray(T[] a) {
		return adpts.toArray(a);
	}

	/**
	 * @return the adpts
	 */
	public ArrayList<Adoption> getAdpts() {
		return adpts;
	}

	/**
	 * @return
	 * @see java.util.Map#values()
	 */
	public Collection<Department> getDepts() {
		return depts.values();
	}

	/**
	 * @return the startDate
	 */
	public Date getStartDate() {
		return startDate;
	}

	/**
	 * @return the endDate
	 */
	public Date getEndDate() {
		return endDate;
	}

	public Map<String, Book> getBooksISBN() {
		HashMap<String,Book> out = new HashMap<String,Book>();
		for (Adoption a : adpts) {
			Book b = a.getBook();
			out.put(String.valueOf(b.getISBN()), b);
		}
		return out;
	}

	public Map<String, Book> getBooksInvNum() {
		HashMap<String,Book> out = new HashMap<String,Book>();
		for (Adoption a : adpts) {
			Book b = a.getBook();
			out.put(b.getInv_num(), b);
		}
		return out;
	}

	@Override
	public int compareTo(Term o) {
		
		int myYear = getYear(), yourYear = o.getYear();
		Semester mySem = getSemester(), yourSem = o.getSemester();
		
		if (myYear == yourYear) {
			if (mySem.equals(Semester.FALL)) {
				if (yourSem.equals(Semester.FALL))
					return 0;
				else
					return -1;
			}
			else if (mySem.equals(Semester.SUMMER_B)) {
				if (yourSem.equals(Semester.FALL))
					return 1;
				else if (yourSem.equals(Semester.SUMMER_B))
					return 0;
				else
					return -1;
			}
			else if (mySem.equals(Semester.SUMMER_A)) {
				if (yourSem.equals(Semester.SUMMER_A))
					return 0;
				else if (yourSem.equals(Semester.SPRING))
					return -1;
				else
					return 1;
			}
			else {
				if (yourSem.equals(Semester.SPRING))
					return 0;
				else
					return -1;
			}
		}
		else if (myYear < yourYear)
			return -1;
		else
			return 1;
	}
}
